#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_compiler
{
    using namespace ns_util;
    using namespace ns_log;

    class Compiler
    {
    public:
        static bool Compile(const std::string &file_name)
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                LOG(ERROR) << "内部错误,创建子进程错误" << std::endl;
                return false;
            }
            else if (pid == 0) // 子进程，进行程序替换
            {
                // 编译的过程可能会报错，将报错的信息从标准错误流重定向到错误文件当中。
                int _stderr = open(PathUtil::CompileError(file_name).c_str(), O_WRONLY | O_CREAT, 644);//写，创建
                if (_stderr < 0)
                {
                    LOG(WARNING) << "没有形成stderr文件" << std::endl;
                    exit(1);
                }

                dup2(_stderr, 2);

                // 子进程进程替换执行编译任务， 采用g++编译,g++ -o ".exe" ".cpp" -std=c++11
                execlp("g++", "g++", "-o", PathUtil::Exe(file_name).c_str(),
                       PathUtil::Src(file_name).c_str(), "-std=c++11", nullptr);

                LOG(ERROR) << "启动编译器g++失败,可能是参数错误" << "\n";//重新替换成功后会不显示这一句
                exit(2);
            }
            else // 父进程等待
            {
                waitpid(pid, nullptr, 0); // man里面查不全，还有个《sys/wait.h》

                if (FileUtil::IsFileExist(PathUtil::Exe(file_name))) // 查询可执行程序是否创建成功
                {
                    LOG(INFO) << PathUtil::Src(file_name)<< "编译成功" << "\n";
                    return true;
                }

                LOG(ERROR) << "编译失败，没有形成可执⾏程序" << "\n";
                return false;
            }
        }
    };
};